# parser.py - Module for parsing whois response data
# Copyright (c) 2008 Andrey Petrov
#
# This module is part of pywhois and is released under
# the MIT license: http://www.opensource.org/licenses/mit-license.php

import re
from util import ip2num
import time
import sys

class PywhoisError(Exception):
    pass


def cast_date(date_str):
    """Convert any date string found in WHOIS to a time object.
    """
    known_formats = [
        '%d-%b-%Y',                 # 02-jan-2000
        '%Y-%m-%d',                 # 2000-01-02
        '%d-%b-%Y %H:%M:%S %Z',        # 24-Jul-2009 13:20:03 UTC
        '%a %b %d %H:%M:%S %Z %Y',  # Tue Jun 21 23:59:59 GMT 2011
        '%Y-%m-%dT%H:%M:%SZ',       # 2007-01-26T19:10:31Z
    ]

    for format in known_formats:
        try:
            return time.strptime(date_str.strip(), format)
        except ValueError, e:
            pass # Wrong format, keep trying
    return None


class WhoisEntry(object):
    """Base class for parsing a Whois entries.
    """
    key_word = 'NetRange:'

    # regular expressions to extract domain data from whois profile
    # child classes will override this
    _regex = {
        'netrange': 'NetRange:\s*(.+)',
        'orgname': 'OrgName:\s*(.+)',
        'country': 'Country:\s*(.+)',
    }

    def __init__(self, whois_server, text, regex=None):
        self.whois_server = whois_server
        self.text = text
        if regex is not None:
            self._regex = regex


    def __getattr__(self, attr):
        """The first time an attribute is called it will be calculated here.
        The attribute is then set to be accessed directly by subsequent calls.
        """
        whois_regex = self._regex.get(attr)
        if whois_regex:
            setattr(self, attr, [item.strip() for item in re.findall(whois_regex, self.text)])
            return getattr(self, attr)
        else:
            raise KeyError('Unknown attribute: %s' % attr)

    def __str__(self):
        """Print all whois properties of domain
        """
        return '\n'.join('%s: %s' % (attr, str(getattr(self, attr))) for attr in self.attrs())


    def attrs(self):
        """Return list of attributes that can be extracted for this domain
        """
        return sorted(self._regex.keys())


class WhoisApnic(WhoisEntry):
    key_word = 'inetnum:'
    _regex = {
        'netrange': 'inetnum:\s*(.+)',
        'orgname': 'descr:\s*(.+)',
        'country': 'country:\s*(.+)',
    }
   
    def __init__(self, whois_server, text):
        WhoisEntry.__init__(self, whois_server, text) 

class EntryUtil(object):
    entrys = [WhoisEntry,
              WhoisApnic,
              ]
    def __init__(self):
        pass
    
    def _load(self,whois_server, text):
        """Given whois output in ``text``, return an instance of ``WhoisEntry`` that represents its parsed contents.
        """

        if text.strip() == 'No whois server is known for this kind of object.':
            raise PywhoisError(text)
    
        for entry in self.entrys:
            if text.find(entry.key_word) > 0:
                return entry(whois_server, text)
        
        raise PywhoisError(text)
    
    def _data4(self,entry):
        ip1, ip2 = entry.netrange[0].split('-')
        country = entry.country[0][:2]
        if country:
            country = country.upper()
        else:
            country = ''
        return ((ip2num(ip1), ip2num(ip2)),(country, entry.orgname[0]))
    
    def loads(self, texts):
        texts.reverse()
        for text in texts:
            try:
                entry = self._load(text[0], text[1])
                return self._data4(entry)
            except:
                pass
            
        return None
            

if __name__ == '__main__':
    text1 = '''
% [whois.apnic.net node-2]
% Whois data copyright terms    http://www.apnic.net/db/dbcopyright.html

inetnum:        114.80.0.0 - 114.95.255.255
netname:        CHINANET-SH
descr:          CHINANET SHANGHAI PROVINCE NETWORK
descr:          China Telecom
descr:          No.31,jingrong street
descr:          Beijing 100032
country:        CN
admin-c:        WWQ4-AP
tech-c:         WWQ4-AP
remarks:        service provider
status:         ALLOCATED PORTABLE
mnt-by:         APNIC-HM
mnt-lower:      MAINT-CHINANET
mnt-lower:      MAINT-CHINANET-SH
changed:        hm-changed@apnic.net 20080514
source:         APNIC
        '''
    text2 = '''
NetRange:       173.208.128.0 - 173.208.255.255
CIDR:           173.208.128.0/17
OriginAS:       AS32097
NetName:        WII-OAK-2
NetHandle:      NET-173-208-128-0-1
Parent:         NET-173-0-0-0-0
NetType:        Direct Allocation
Comment:        http://www.wholesaleinternet.com
RegDate:        2009-12-17
Updated:        2009-12-17
Ref:            http://whois.arin.net/rest/net/NET-173-208-128-0-1

OrgName:        WholeSale Internet, Inc.
OrgId:          WHOLE-125
Address:        324 E. 11th St.
Address:        Suite 1000
City:           Kansas City
StateProv:      MO
PostalCode:     64106
Country:        US
RegDate:        2003-09-24
Updated:        2009-06-03
Comment:        http://www.wholesaleinternet.net
Ref:            http://whois.arin.net/rest/org/WHOLE-125
    '''
    entry = EntryUtil()
    print entry.loads({'a':text1, 'b':text2})

